package com.android.people;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Set;

import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.FileObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;

public class SlideImageViewService extends Service {
    private static final String TAG = "SlideImageViewService";
    private static final boolean DEBUG = false;
    
    public static final String WIDGET_IDS = "widgetids";
    public static final String WIDGET_ID = "widgetid";
    public static final String IMAGE_PATHS = "imagepaths";
    public static final String BCR_DELETE_CLIENT = "deleteclient";
    public static final String ACTION_CLICK_WIDGET = "clickwidget";
    public static final String ACTION_CLICK_WIDGET_SERVICE = "clickwidget_service";
    public static final String CLICK_VIEW_ID = "clickViewID";
    public static final String GALLARY_PATH = "gallary_path";
    public static final String GALLARY_SHOW_NAME = "gallary_show_name";
    public static final String PREVIEW_path = "preview_path";
    public static final String UPDATE_TIME = "update_time";
    
    private Context mContext;

    //handle event index
    private final static int UPDATE_NEW_IMAGE = 0;
    private static final int REFRESH_LIST = 1;
    
    //the private const data
    private static final int DEFAULT_UPDATE_TIME = 1;
    private static String IMAGE_SUBFIX = ".jpg";
    private static String IMAGE_SUBFIX1 = ".png";
    private static String CLIENT_INTER_SPLIT = ":";
    private static String CLIENT_SPLIT = ";";
    private static String DATABASE_INIT = "database_init";
    private static final String CLIENT_LIST = "clientlist";
    
    private SharedPreferences mSharedPreferences;
    private SharedPreferences.Editor mEditor;
    private BroadcastReceiver mSDChangedBCR;
    
    private PhotoDatabaseHelper mdb;
    private boolean mStopForSDUnmount = false;
    
    private class Client {
        final int mClientId;
        final int mUpdateRate;
        final String mScanPath;
        ImageListManager mListManager;
        List<Long> mIdList;
        
        int mCurrentShowIndex;
        String mUpdateFilePath;
        boolean mNeedUpdate;
        int mReceviedTimes;
        
        Client(int clientID, int updateRate, String scanPath) {
            mClientId = clientID;
            mUpdateRate = updateRate;
            mScanPath = scanPath;
            mListManager = new ImageListManager(mContext, mScanPath);
            mIdList = mListManager.getIDList();
            
            mCurrentShowIndex = 0;
            mUpdateFilePath = null;
            mNeedUpdate = false;
            mReceviedTimes = 0;
        }
        
        void updateClientStatus() {
            ++mReceviedTimes;
            if (mReceviedTimes >= mUpdateRate && mIdList.size() > 0) {
                mReceviedTimes = 0;
                mNeedUpdate = true;
            }
        }
        
        long getUpdateFileId() {
            if (mNeedUpdate == true) {
                mNeedUpdate = false;
                if (mCurrentShowIndex >= mIdList.size()) {
                    mCurrentShowIndex = 0;
                }
                if (mIdList.size() == 0) {
                    return -1;
                }
                return mIdList.get(mCurrentShowIndex++);
            }
            return -1;
        }
        
        void refreshFileList() {
            mListManager.refreshList();
            mIdList = mListManager.getIDList();
//            for (int index = 0; index < mIdList.size(); ++index) {
//                LOGD("id = " + mIdList.get(index));
//            }
        }
    }
    private List<Client> mClientList;
    private List<Client> mUpdateClientList;
    
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch(msg.what) {
            case UPDATE_NEW_IMAGE:
                updateImage();
                return;
            case REFRESH_LIST:
                refreshAllFileList();
                mHandler.sendEmptyMessage(UPDATE_NEW_IMAGE);
                break;
            }
            super.handleMessage(msg);
        }
    };

    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (mClientList.size() == 0) {
                stopSelf();
            }
            if (mStopForSDUnmount == false) {
            	mUpdateClientList.clear();
                LOGD("~~~~~~ receive the time changed ~~~~~~~~~~~~");
                for (Client c : mClientList) {
                    c.updateClientStatus();
                    if (c.mNeedUpdate == true) {
                        if (mUpdateClientList.contains(c) == false) {
                        	mUpdateClientList.add(c);
                        }
                    }
                }
                if (mUpdateClientList.size() > 0) {
                    mHandler.sendEmptyMessage(UPDATE_NEW_IMAGE);
                }
            }
        }
    };
    
    private final BroadcastReceiver mIntentDeleteClient = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            LOGD("(((((( receive delete broadcasr ))))))))");
            int id = intent.getIntExtra(WIDGET_ID, -1);
            if (id != -1) {
                for (Client c : mClientList) {
                    if (c.mClientId == id) {
                        LOGD(" ((((( delete the client id = " + c.mClientId + " ))))))");
                        mClientList.remove(c);
                        mUpdateClientList.remove(c);
                    }
                }
                StringBuilder builder = new StringBuilder();
                for (Client c : mClientList) {
                	builder.append(String.valueOf(c.mClientId)).append(CLIENT_INTER_SPLIT)
                		.append(c.mScanPath).append(CLIENT_INTER_SPLIT).append(String.valueOf(c.mUpdateRate))
                		.append(CLIENT_SPLIT);
                }
                if (builder.length() > 0) {
                	mEditor.putString(CLIENT_LIST, builder.substring(0, (builder.length() - 1)));
                } else {
                	mEditor.putString(CLIENT_LIST, "");
                }
                mEditor.commit();
                if (mClientList.size() == 0) {
                    stopSelf();
                }
            }
        }
    };
    
    private final BroadcastReceiver mLanuchGallary = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            LOGD("$$$$$$ service receive the intent $$$$$");
            if (intent.getAction().equals(ACTION_CLICK_WIDGET_SERVICE) == true) {
//                Intent intent = new Intent(context.getApplicationContext(), );
                LOGD("start the gallary activity, appwidget id = " 
                     + intent.getIntExtra(SlideImageViewService.WIDGET_ID, -1) + "...........");
                int appId = intent.getIntExtra(WIDGET_ID, -1);
                if (appId != -1) {
                    Intent intentSend = new Intent(context.getApplicationContext(), GallaryActivity.class);
                    intentSend.setAction("android.intent.action.MAIN");
                    intentSend.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    
                    for (Client c : mClientList) {
                        if (c.mClientId == appId) {
                            intentSend.putExtra(GALLARY_PATH, c.mScanPath);
                            if (c.mUpdateFilePath != null) {
                                intentSend.putExtra(GALLARY_SHOW_NAME, c.mUpdateFilePath);
                            }
                            break;
                        }
                    }
                    context.startActivity(intentSend);
                }
            }
        }
    };
    
    private final BroadcastReceiver mScanFinished = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            LOGD("++++++++++ receivew scan finish BRC ++++++++++++");
            if (intent.getAction().equals(Intent.ACTION_MEDIA_SCANNER_FINISHED) == true) {
                mHandler.sendEmptyMessage(REFRESH_LIST);
            }
        }
    };
    
    @Override
    public void onCreate() {
        super.onCreate();
        LOGD("create service");
        this.setForeground(true);
        mContext = this;
        mClientList = new ArrayList<Client>();
        mUpdateClientList = new ArrayList<Client>();
        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        mEditor = mSharedPreferences.edit();
        boolean inited = mSharedPreferences.getBoolean(DATABASE_INIT, false);
        if (inited == false) {
            File file = this.getDatabasePath(PhotoDatabaseHelper.DATABASE_NAME);
            if (file.exists() == true) {
                LOGD("delete the old database");
                file.delete();
            }
        }

        mdb = new PhotoDatabaseHelper(this);
        registerDeleteClient();
        registerSDBCR();
        registerLanuchActivity();
        registerMediaScanFinish();
        registerTimeBCR();
        
		String clientList = mSharedPreferences.getString(CLIENT_LIST, "");
		LOGD("Client list save = " + clientList);
		if (clientList.equals("") == false) {
			String[] list = clientList.split(CLIENT_SPLIT);
			for (String item : list) {
				LOGD(" the item is = " + item);
				String[] info = item.split(CLIENT_INTER_SPLIT);
				int id = Integer.valueOf(info[0]);
				Client c = new Client(id, Integer.valueOf(info[2]), info[1]);
				mClientList.add(c);
				c.mNeedUpdate = true;
				if (mUpdateClientList.contains(c) == false) {
					mUpdateClientList.add(c);
				}
			}
			if (mUpdateClientList.size() > 0) {
				if (mdb != null) {
					mdb.close();
				}
				refreshAllFileList();
				mHandler.sendEmptyMessage(UPDATE_NEW_IMAGE);
			}
		}
	}

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        
        LOGD(" on start service");
        String scanPath = intent.getStringExtra(PREVIEW_path);
        int updateRate = intent.getIntExtra(UPDATE_TIME, DEFAULT_UPDATE_TIME);
        int clientId = intent.getIntExtra(SlideImageViewService.WIDGET_ID, -1);
        
        if (clientId != -1 && scanPath != null) {
        	//add a new client 
            Client c = new Client(clientId, updateRate, scanPath);
            mClientList.add(c);
            c.mNeedUpdate = true;
            if (mUpdateClientList.contains(c) == false) {
            	mUpdateClientList.add(c);
            }
        
            if (mdb != null) {
                mdb.close();
            }
            
            String clientList = mSharedPreferences.getString(CLIENT_LIST, "");
            String thisClient = String.valueOf(clientId) + CLIENT_INTER_SPLIT + scanPath 
            						+ CLIENT_INTER_SPLIT + String.valueOf(updateRate);
            LOGD("@@@@@@@@@ this client = " + thisClient + " @@@@@@@@@");
            if (clientList.equals("") == true) {
                clientList = thisClient;
            } else {
                clientList = clientList + CLIENT_SPLIT + thisClient;
            }
            LOGD("@@@@@@@@@ Client list now = " + clientList + " @@@@@@@@@@@");
            mEditor.putString(CLIENT_LIST, clientList);
            mEditor.putBoolean(DATABASE_INIT, true);
            mEditor.commit();
            refreshAllFileList();
            mHandler.sendEmptyMessage(UPDATE_NEW_IMAGE);
        } else {
            int[] ids = intent.getIntArrayExtra(WIDGET_IDS);
            if (ids != null) {
                boolean needupdate = false;
                LOGD(" &&&&&& check the service to init client &&&&&& ");
                for (int index = 0; index < ids.length; ++index) {
                    LOGD("------ this id = " + ids[index] + " --------");
                    boolean clientInList = false;
                    for (Client c : mClientList) {
                        if (c.mClientId == ids[index]) {
                            clientInList = true;
                        }
                    }
                    if (clientInList == false) {
                        String clientList = mSharedPreferences.getString(CLIENT_LIST, "");
                        if (clientList.equals("") == true) {
                            return;
                        }
                        LOGD("Client list save = " + clientList);
                        String[] list = clientList.split(CLIENT_SPLIT);
                        for (String item : list) {
                            LOGD(" the item is = " + item);
                            String[] info = item.split(CLIENT_INTER_SPLIT);
                            int id = Integer.valueOf(info[0]);
                            if (id == ids[index]) {
                                Client c = new Client(id, Integer.valueOf(info[2]), info[1]);
                                mClientList.add(c);
                                c.mNeedUpdate = true;
                                if (mUpdateClientList.contains(c) == false) {
                                    mUpdateClientList.add(c);
                                }
                                needupdate = true;
                            }
                        }
                    }
                }
                if (needupdate == true) {
                    if (mdb != null) {
                        mdb.close();
                    }
                    refreshAllFileList();
                    mHandler.sendEmptyMessage(UPDATE_NEW_IMAGE);
                }
            }
        }
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        LOGD("xxxxxxx destroy the services xxxxxxxxxxx");
        mHandler = null;
        this.unregisterReceiver(mIntentReceiver);
        this.unregisterReceiver(mLanuchGallary);
        this.unregisterReceiver(mIntentDeleteClient);
        this.unregisterReceiver(mScanFinished);
        if (mSDChangedBCR != null) {
            unregisterReceiver(mSDChangedBCR);
        }
//        mThemeListObserver.stopWatching();
//        mThemeListObserver = null;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }
    
    private void refreshAllFileList() {
        if (mClientList != null) {
            for (Client c : mClientList) {
                c.refreshFileList();
            }
        }
    }

    private void updateImage() {
        LOGD(" ++++++++ service update image ++++++++");
        Intent resultValue = new Intent("android.appwidget.action.APPWIDGET_UPDATE");
        resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { -1 });
        if (mUpdateClientList != null && mUpdateClientList.size() > 0) {
            int[] ids = new int[mUpdateClientList.size()];
            long[] fileIds = new long[mUpdateClientList.size()];
            for (int index=0; index < mUpdateClientList.size(); ++index) {
            	Client c = mUpdateClientList.get(index);
				long updateFileId = c.getUpdateFileId();
				if (updateFileId != -1) {
					if (updateDB(c, updateFileId) == true) {
						ids[index] = c.mClientId;
						fileIds[index] = updateFileId;
					}
				}
            }
            mUpdateClientList.clear();
			resultValue.putExtra(IMAGE_PATHS, fileIds);
			resultValue.putExtra(WIDGET_IDS, ids);
			LOGD("   send broadcast to update info to update ");
			mContext.sendBroadcast(resultValue);
        } else {
            LOGD("   send broadcast to update empty show ");
            mContext.sendBroadcast(resultValue);
        }
    }
    
    private boolean updateDB(Client c, long fileId) {
        LOGD(" update " + fileId + " to database, current time = " + getCurrentTime());
        boolean addfile = false;
        if (mdb.contain(fileId) == false && fileId != -1) {
            LOGD(" ((Begin load image)), current time = " + getCurrentTime());
            Bitmap bm = c.mListManager.thumbBitmap(fileId);
            LOGD(" ((end load image)), current time = " + getCurrentTime());
            if (bm != null) {
                boolean ret = mdb.setPhoto(fileId, bm);
                if (ret == false) {
                    LOGD("insert the file : " + fileId + " failed");
                } else {
                    addfile = true;
                }
            } else {
                //roll back
//                mImageIndex = mImageIndex - 1;
            }
        } else {
            addfile = true;
        }
        
        mdb.close();
        LOGD(" ending .... update " + fileId + " to database, current time = " + getCurrentTime());
        return addfile;
    }
    
    private void registerMediaScanFinish() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
        filter.addDataScheme("file");
        registerReceiver(mScanFinished, filter);
    }
    
    private void registerLanuchActivity() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(this.ACTION_CLICK_WIDGET_SERVICE);
        registerReceiver(mLanuchGallary, filter, null, mHandler);
    }
    
    private void registerDeleteClient() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BCR_DELETE_CLIENT);
        this.registerReceiver(mIntentDeleteClient, filter, null, mHandler);
    }
    
    private void registerTimeBCR() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        this.registerReceiver(mIntentReceiver, filter, null, mHandler);
    }
    
    private void registerSDBCR() {
        if (mSDChangedBCR == null) {
            mSDChangedBCR = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
                        mStopForSDUnmount = true;
                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                        mStopForSDUnmount = false;
                        mHandler.sendEmptyMessage(REFRESH_LIST);
                    }
                }
            };
            IntentFilter iFilter = new IntentFilter();
            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
            iFilter.addDataScheme("file");
            registerReceiver(mSDChangedBCR, iFilter);
        }
    }
    
    private class SDFileObserver extends FileObserver {
        
        public void onEvent(int event, String path) {
            if (mHandler != null) {
                mHandler.sendEmptyMessage(REFRESH_LIST);
            }
        }
        
        public void close() {
            super.finalize();
        }

        private SDFileObserver(String path) {
            super(path, FileObserver.DELETE | FileObserver.CREATE | FileObserver.MOVE_SELF | FileObserver.MOVED_TO);
        }
    }
    
//    public static class BitmapUtils {
//        public static Bitmap createSmallBitmap(Context context, String fullpath) {
//            LOGD("          Beign to caculate the bitmap " + fullpath);
//            Bitmap bm = BitmapFactory.decodeFile(fullpath);
//            if (bm != null) {
//                DisplayMetrics display = context.getResources().getDisplayMetrics();
//                int maxDimension = Math.min(display.heightPixels, display.widthPixels);
//                maxDimension = maxDimension / 2;
//
//                int degree = 0;
//                try {
//                    ExifInterface exif = new ExifInterface(fullpath);
//                    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
//                    if (orientation != -1) {
//                        // We only recognize a subset of orientation tag values.
//                        switch (orientation) {
//                        case ExifInterface.ORIENTATION_ROTATE_90:
//                            degree = 90;
//                            break;
//                        case ExifInterface.ORIENTATION_ROTATE_180:
//                            degree = 180;
//                            break;
//                        case ExifInterface.ORIENTATION_ROTATE_270:
//                            degree = 270;
//                            break;
//                        default:
//                            degree = 0;
//                            break;
//                        }
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//                int base = Math.min(bm.getWidth(), bm.getHeight());
//                double scaled = 1.0;
//                if (base > maxDimension) {
//                    if (base == bm.getWidth()) {
//                        scaled = ((double) maxDimension / (double) base);
//                    } else if (base == bm.getHeight()) {
//                        scaled = ((double) maxDimension / (double) base);
//                    }
//                }
//                Matrix m = new Matrix();
//                m.setRotate((float) degree, bm.getWidth() / 2, bm.getHeight() / 2);
//                m.postScale((float) scaled, (float) scaled);
//                Bitmap bmScaled = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
//
//                Bitmap croppedImage = Bitmap.createBitmap(maxDimension, maxDimension, Bitmap.Config.RGB_565);
//                Canvas canvas = new Canvas(croppedImage);
//
//                Rect dstRect = new Rect(0, 0, maxDimension, maxDimension);
//
//                int srcWidth = bmScaled.getWidth();
//                int srcHeight = bmScaled.getHeight();
//
//                Rect srcRect = new Rect(0, 0, srcWidth, srcHeight);
//                if (srcWidth >= maxDimension) {
//                    srcRect.left = (srcWidth - maxDimension) / 2;
//                    srcRect.right = (srcWidth - maxDimension) / 2 + maxDimension;
//                } else {
//                    dstRect.left = (maxDimension - srcWidth) / 2;
//                    dstRect.right = (maxDimension - srcWidth) / 2 + srcWidth;
//                }
//
//                if (srcHeight >= maxDimension) {
//                    srcRect.top = (srcHeight - maxDimension) / 2;
//                    srcRect.bottom = (srcHeight - maxDimension) / 2 + maxDimension;
//                } else {
//                    dstRect.top = (maxDimension - srcHeight) / 2;
//                    dstRect.bottom = (maxDimension - srcHeight) / 2 + maxDimension;
//                }
//                canvas.drawBitmap(bmScaled, srcRect, dstRect, null);
////                LOGD("The src size is : " + bmScaled.getWidth() + " " + bmScaled.getHeight());
//                if (bm != bmScaled) {
//                    bm.recycle();
//                }
////                LOGD("The target image src rect : " + srcRect.left + " " + srcRect.top + " " + srcRect.right + " "
////                        + srcRect.bottom);
////                LOGD("The target image target rect : " + dstRect.left + " " + dstRect.top + " " + dstRect.right + " "
////                        + dstRect.bottom);
//
//                return bmScaled;
//            }
//
//            return null;
//        }
//    }
    
    public static class BitmapAdapter implements Adapter {
        private ArrayList<Bitmap> mBmapList;
        private int mIdx;

        public int GetInitIndex() {
            return mIdx;
        }

        public BitmapAdapter(ArrayList<Bitmap> bmapList, int idx) {
            mBmapList = bmapList;
            mIdx = idx;
        }

        public void registerDataSetObserver(DataSetObserver observer) {
        }

        public boolean isEmpty() {
            return false;
        }

        public void unregisterDataSetObserver(DataSetObserver observer) {
        }

        public int getCount() {
            return mBmapList.size();
        }

        public Object getItem(int position) {
            return mBmapList.get(position);
        }

        public long getItemId(int position) {
            return 0;
        }

        public boolean hasStableIds() {
            return false;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            return null;
        }

        public int getNewSelectionForKey(int currentSelection, int keyCode,
                KeyEvent event) {
            return 0;
        }

        public int getViewTypeCount() {
            return 0;
        }

        public int getItemViewType(int position) {
            return 0;
        }
    }
    
    public static void LOGD(String msg) {
        if (DEBUG == true) {
            Log.d(TAG, msg);
        }
    }
    
    public static String getCurrentTime() {
        Calendar cl = Calendar.getInstance();
        return cl.get(Calendar.HOUR_OF_DAY) + "H " + cl.get(Calendar.MINUTE) + "M "
                + cl.get(Calendar.SECOND) + "S " + cl.get(Calendar.MILLISECOND) + "ms";
    }
}
